﻿using Ly.EBussiness.Core.Dto.Order;
using Ly.EBussiness.EntityFrameworkCore;
using Ly.EBussiness.EntityFrameworkCore.Auth.User;
using Ly.EBussiness.EntityFrameworkCore.Entity;
using Volo.Abp;
using Volo.Abp.ObjectMapping;

namespace Ly.EBussiness.Core.Service.impl;

public class OrderService : IOrderService
{
    private readonly IReadOnlyQueryRepository _readOnlyQueryRepository;
    private readonly EBussinessDbContext _dbContext;
    private readonly ICurrentUser _currentUser;
    private readonly IObjectMapper _objectMapper;


    /// <summary>
    /// 
    /// </summary>
    /// <param name="readOnlyQueryRepository"></param>
    /// <param name="dbContext"></param>
    /// <param name="currentUser"></param>
    /// <param name="objectMapper"></param>
    public OrderService(IReadOnlyQueryRepository readOnlyQueryRepository,
        EBussinessDbContext dbContext, ICurrentUser currentUser, IObjectMapper objectMapper)
    {
        _readOnlyQueryRepository = readOnlyQueryRepository;
        _dbContext = dbContext;
        _currentUser = currentUser;
        _objectMapper = objectMapper;
    }

    /// <summary>
    /// 查询自己的订单列表
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public async Task<OrderListPageOutput> QueryOrdersInfoPageAsync(OrderListInput input)
    {
        var allPagedAsync = await _readOnlyQueryRepository.GetAllPagedAsync<OrderListDto, OrderListInput>(input);
        return new OrderListPageOutput(allPagedAsync);
    }

    /// <summary>
    /// 查询自己的订单详情
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public async Task<OrderDetailsDto> QueryOrderDetailAsync(OrderDetailsInput input)
    {
        var firstOrDefaultAsync = await _readOnlyQueryRepository.FirstOrDefaultAsync<OrderInfo>(new { input.OrderId });
        var orderDetails = await _readOnlyQueryRepository.QueryAsync<OrderDetail>(new { input.OrderId });
        var list = orderDetails.Select(x => x.PutGoodsId).Distinct().ToList();
        var putGoodsList = await _readOnlyQueryRepository.QueryAsync<PutGoods>(new { id = list });
        var result = new OrderDetailsDto();
        result.Init(firstOrDefaultAsync, orderDetails, putGoodsList);
        return result;
    }

    /// <summary>
    /// 下单-
    /// 用户是否登录
    /// 1.检查入参中得快递信息
    /// 2.检查商品是否下架 (下架)
    /// 3.检查用户是否有未支付订单
    /// 
    ///
    ///
    ///
    ///
    /// 
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public async Task<bool> OrderAsync(OrderDto input)
    {
        if (_currentUser.Id.IsNullOrWhiteSpace())throw new Exception("请先登录");
        //效验
        input.Check();
        //验证--上否下架
        var putGoodsList = await _readOnlyQueryRepository.QueryAsync<PutGoods>(new { Id = input.PutGoodForOrders.Select(x => x.PutGoodId) });
        if (putGoodsList.Any(x => x.IsDeleted)) throw new BusinessException("商品已下架,请重新下单");
        if (putGoodsList.Count != input.PutGoodForOrders.Count) throw new BusinessException("参数错误 ,重新下单");
        
        await using var dbContextTransaction = await _dbContext.Database.BeginTransactionAsync();
        var orderInfo = new OrderInfo { OrderStatus = OrderStatus.UnPaid, UserId = _currentUser.Id};
        await _dbContext.OrderInfos.AddAsync(orderInfo);
        await _dbContext.SaveChangesAsync();
        var OrderDetails = new List<OrderDetail>();
        putGoodsList.AsParallel().ForAll(x =>
        {
            var orderDetail = new OrderDetail { OrderId = orderInfo.OrderId };
            var putGoodForOrder = input.PutGoodForOrders.First(y => x.Id == y.PutGoodId);
            orderDetail.PutGoodsId = x.Id;
            orderDetail.Sum = putGoodForOrder.Sum;
            orderDetail.TotalPrice = x.OriginalPrice * putGoodForOrder.Sum;
            OrderDetails.Add(orderDetail);
        });
        orderInfo.TotalAmount = OrderDetails.Sum(x => x.TotalPrice);
        await _dbContext.OrderDetails.AddRangeAsync(OrderDetails);
        var expressInfo = _objectMapper.Map<ExpressInfoDto, ExpressInfo>(input.ExpressInfoDto);
        expressInfo.OrderId = orderInfo.OrderId;
        await _dbContext.ExpressInfos.AddAsync(expressInfo);
        await _dbContext.SaveChangesAsync();
        await dbContextTransaction.CommitAsync();
        return true;
    }
}